/* 类模板实现C++ STL中的 vector
 *
 * 容器空间适配器allocator:（做四件事情）
 * 内存开辟/内存释放   对象构造/对象析构
 * */
#include <iostream>
using namespace std;

//定义容器的空间配置器
template<typename T>
class Allocator{
public:
    T* allocate(size_t size){      //负责内存开辟
        return (T*) malloc(sizeof(T) *size);
    }

    void deallocate(void *p){       //负责内存释放
        free(p);
    }

    void construct(T* p,const T& val){      //负责对象构造
        new (p) T(val);         //定位new
    }

    void destroy(T *p){     //负责对象析构
        p->~T();        //~T()代表了T类型的析构函数
    }
};

//容器底层内存开辟，内存释放，对象构造和析构，都通过空间适配器allocator来实现
template<typename T,typename Alloc=Allocator<T>>
class Vector{
private:
    T* _first;      //指向数组起始的位置
    T* _last;       //指向数组中有效元素的后继位置
    T* _end;        //指向数组空间的后继位置
    Alloc _allocator;   //定义容器的空间配置器对象

    void expand(){  //容器的2倍扩容实现
        int size=_end-_first;
        //T* ptmp=new T[size*2];
        T* ptmp=_allocator.allocate(2*size);
        for (int i = 0; i < size; ++i) {
            //ptmp[i]=_first[i];
            _allocator.construct(ptmp+i,_first[i]);
        }
        //delete[] _first;
        for (T* p = _first; p !=_last ; ++p) {
            _allocator.destroy(p);
        }
        _allocator.deallocate(_first);

        _first=ptmp;
        _last=_first+size;
        _end=_first+2*size;
    }

public:
    Vector(int size=10){
        //需要把内存开辟和对象构造分开
        //_first=new T[size];
        _first=_allocator.allocate(size);
        _last=_first;
        _end=_first+size;
    }
    ~Vector(){
        //析构容器有效的元素，然后释放_first指针指向的堆内存
        //delete []_first;
        for (T* p = _first; p!=_last; ++p) {
            _allocator.destroy(p);      //把_first指针指向的数组有效元素进行析构操作
        }
        _allocator.deallocate(_first);  //释放堆上的数组内存
        _first=_last=_end= nullptr;
    }
    Vector(const Vector<T> &rhs){
        int size=rhs._end-rhs._first;
        //_first=new T[size];
        _first=_allocator.allocate(size);

        int len=rhs._last-rhs._first;
        for (int i = 0; i < len; ++i) {
            //_first[i]=rhs._first[i];
            _allocator.construct(_first+i,rhs._first[i]);
        }
        _last=_first+len;
        _end=_first+size;
    }
    Vector<T>& operator=(const Vector<T> &rhs){
        if (this==&rhs){
            return *this;
        }
        //delete []_first;
        for (T* p = _first; p!=_last; ++p) {
            _allocator.destroy(p);      //把_first指针指向的数组有效元素进行析构操作
        }
        _allocator.deallocate(_first);  //释放堆上的数组内存

        int size=rhs._end-rhs._first;
        //_first=new T[size];
        _first=_allocator.allocate(size);

        int len=rhs._last-rhs._first;
        for (int i = 0; i < len; ++i) {
            //_first[i]=rhs._first[i];
            _allocator.construct(_first+i,rhs._first[i]);
        }
        _last=_first+len;
        _end=_first+size;
        return *this;
    }
    void push_back(const T& val){
        if (full()){
            expand();
        }
        //*_last++=val;     _last指针指向的内存构造一个值为val的对象
        _allocator.construct(_last,val);
        _last++;
    }

    void pop_back(){
        if (empty()){
            return;
        }
        //--_last;      //不仅要把_last指针--，还需要析构删除的元素
        --_last;
        _allocator.destroy(_last);
    }
    T back() const{     //返回容器末尾元素的值
        return *(_last-1);
    }
    bool full() const{
        return _last==_end;
    }
    bool empty() const{
        return _first==_last;
    }
    int size() const{
        return _last-_first;
    }
};

class Test{
public:
    Test(){
        cout<<"test()"<<endl;
    }
    ~Test(){
        cout<<"~test()"<<endl;
    }
    Test(const Test&){
        cout<<"Test(const Test&)"<<endl;
    }
};

int main(){
    /*
    Vector<int> vec;
    for (int i = 0; i < 10; ++i) {
        vec.push_back(rand()%100);
    }
    while (!vec.empty()){
        cout<<vec.back()<<" ";
        vec.pop_back();
    }
     */
    Test t1,t2,t3;
    cout<<"--------------"<<endl;
    Vector<Test> vec;
    vec.push_back(t1);
    vec.push_back(t2);
    vec.push_back(t3);
    cout<<"--------------"<<endl;
    vec.pop_back();     //只需要析构对象，要把对象的析构和内存释放分离开
    cout<<"--------------"<<endl;
    return 0;
}